use chrono::{DateTime, Utc};
use dashmap::DashMap;
use lazy_static::lazy_static;
use std::net::IpAddr;

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct RegisteredNode {
    pub id: String,
    pub hostname: String,
    pub ip: String,
    pub tags: Vec<String>,
    pub version: String,
    pub last_seen: DateTime<Utc>,
}

pub struct NodeRegistry {
    inner: DashMap<String, RegisteredNode>,
}

impl NodeRegistry {
    pub fn new() -> Self {
        Self { inner: DashMap::new() }
    }

    pub fn insert_or_update(&self, node: RegisteredNode) {
        self.inner.insert(node.id.clone(), node);
    }

    pub fn list(&self) -> Vec<RegisteredNode> {
        self.inner.iter().map(|kv| kv.value().clone()).collect()
    }

    pub fn get(&self, id: &str) -> Option<RegisteredNode> {
        self.inner.get(id).map(|v| v.clone())
    }

    pub fn update_last_seen(&self, id: &str, ts: DateTime<Utc>) {
        if let Some(mut entry) = self.inner.get_mut(id) {
            entry.last_seen = ts;
        }
    }

    pub fn select_by_tags(&self, tags: &[String]) -> Vec<RegisteredNode> {
        self.inner
            .iter()
            .filter(|kv| {
                let node_tags = &kv.value().tags;
                tags.iter().all(|t| node_tags.contains(t))
            })
            .map(|kv| kv.value().clone())
            .collect()
    }

    pub fn select_by_ip_prefix(&self, prefix: &str) -> Vec<RegisteredNode> {
        self.inner
            .iter()
            .filter(|kv| kv.value().ip.starts_with(prefix))
            .map(|kv| kv.value().clone())
            .collect()
    }
}

lazy_static! {
    pub static ref NODE_REGISTRY: NodeRegistry = NodeRegistry::new();
}


